#!/usr/bin/perl -I./lib
# $Id: protocol-dump.pl,v 1.5 2004/08/02 17:55:36 tvierling Exp $

use strict;
use Carp qw(verbose);
use Sendmail::PMilter qw(:all);
use Getopt::Long;
use IntelSpam::Plugins;
use IntelSpam::Config;
use IntelSpam::Score;
use Data::Dumper;
use POSIX qw(setsid);
use LWP::Simple;
use Log::Log4perl qw( get_logger );



my %log_levels = ( 0 => 'DEBUG', 1 => 'INFO', 2 => 'WARNING', 3 => 'ERROR' );


# milter name should be the one used in sendmail.mc/sendmail.cf
#my $miltername = shift @ARGV || die "usage: $0 miltername\n";

my %cbs;

my $config_file = '/etc/intelspam.conf';
my $milter_name = 'intelspam';

my $result = GetOptions("config|c:s" => \$config_file,
			"milter|m:s" => \$milter_name);

my $plugins = new IntelSpam::Plugins;
my $config = new IntelSpam::Config;
$config->init($config_file);


my $log_level = $log_levels{$config->getcfg('log_level')};
#check if there's a logging filter


print "Log Level: $log_level\n";
my $conf = "
	log4perl.rootLogger          = $log_level, Logfile, Screen

	log4perl.appender.Logfile          = Log::Log4perl::Appender::File
	log4perl.appender.Logfile.filename = /var/log/intelspam.log
	log4perl.appender.Logfile.layout   = Log::Log4perl::Layout::PatternLayout
	log4perl.appender.Logfile.layout.ConversionPattern = %d %p> %F{1}:%L %c - %m%n

	log4perl.appender.Screen         = Log::Log4perl::Appender::Screen
	log4perl.appender.Screen.stderr  = 0
	log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
";

if(defined($config->getcfg('logging_filter'))){
	my $logging_filter_logfile = $config->getcfg('logging_filter')->{'log_file'};
	$conf .= "

		log4perl.category.LoggingFilter = INFO, LoggingFilterFile

		log4perl.appender.LoggingFilterFile          = Log::Log4perl::Appender::File
		log4perl.appender.LoggingFilterFile.filename = $logging_filter_logfile
		log4perl.appender.LoggingFilterFile.layout   = Log::Log4perl::Layout::PatternLayout
		log4perl.appender.LoggingFilterFile.layout.ConversionPattern = %d %p> %F{1}:%L %c - %m%n
	";
}


Log::Log4perl::init( \$conf );

my $logger = get_logger("Intelspam");


$plugins->setcfg($config);
$plugins->read_config;

for my $cb (qw(close helo abort eoh)) {
	$cbs{$cb} = sub {
		my $ctx = shift;
	
		$logger->info("$$: $cb: @_");
		SMFIS_CONTINUE;
	}
}

$cbs{envfrom} = sub {
	my $ctx = shift;
	my @args = @_;
	$logger->debug("$$: envfrom: @_");
	$plugins->filter_envfrom($ctx, shift);
	SMFIS_CONTINUE;
};

$cbs{envrcpt} = sub {
	my $ctx = shift;
	my @args = @_;
	$logger->debug("$$: envrcpt: @_");
	$plugins->filter_envrcpt($ctx, shift);
	SMFIS_CONTINUE;
};
$cbs{connect} = sub {
	my $ctx = shift;
	my $host = shift;
	$logger->info("$$: connect: @_");
	my $pscore = new IntelSpam::Score;
	
	my %mypriv = { 'score' => 0, 'content-type' => 'text/plain' };
	$mypriv{'score'} = $pscore;
	$ctx->setpriv(\%mypriv);
	$plugins->filter_connect($ctx, $host);
	SMFIS_CONTINUE;
};
$cbs{header} = sub {
	my $ctx = shift;
	my @args = @_;
	$logger->debug("$$: header: @_");
	$plugins->filter_header($ctx, $args[0], $args[1]);
	SMFIS_CONTINUE;
};

$cbs{body} = sub {
	my ($ctx, $body) = @_;
	$logger->debug("$$: receiving body");
	defined($ctx->getpriv()->{'body'}) or $ctx->getpriv()->{'body'} = '';
	$ctx->getpriv()->{'body'} .= $body;
	SMFIS_CONTINUE;
};

$cbs{eom} = sub {
	my $ctx = shift;
	my @args = @_;
	$plugins->filter_body($ctx, $ctx->getpriv()->{'body'});
	my $pscore =  $ctx->getpriv()->{'score'};
	my $score = $pscore->score();
	my $status = "NO";

	
	if(int($score) > int($config->getcfg('threshold'))){
		$status = "YES";
	}
	$ctx->addheader("X-Spam-Status", $status);
	$ctx->addheader("X-Spam-Report", $pscore->tests());
	$ctx->addheader("X-Spam-Score", "$score;");
	$ctx->addheader("X-Spam-Filter", "IntelSpam v1.0");

	$logger->info("X-Spam-Status: $status");
	$logger->debug("X-Spam-Report: ".$pscore->tests());
	$logger->debug("X-Spam-Score: $score;");
	
	SMFIS_CONTINUE;
};

my $milter = new Sendmail::PMilter;

$milter->auto_setconn($milter_name);
$milter->register($milter_name, \%cbs, SMFI_CURR_ACTS);

my $dispatcher = Sendmail::PMilter::prefork_dispatcher(
	max_children => 10,
	max_requests_per_child => 100,
);

$milter->set_dispatcher($dispatcher);

# flush the buffer
#$| = 1;

# daemonize the program
#&daemonize;

$milter->main();

sub daemonize {
    chdir '/'                 or die "Can't chdir to /: $!";
    open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
    defined(my $pid = fork)   or die "Can't fork: $!";
    exit if $pid;
    setsid                    or die "Can't start a new session: $!";
    umask 0;
}
